using System;
using System.Collections.Generic;
using System.Threading;

namespace MEA.AE_Data.Access
{
	public class KWP2000
	{
		private const int peyLoadLenSF = 7;

		private const int peyLoadLenFF = 6;

		private const int peyLoadLenCF = 7;

		private const byte SINGLE_FRAME = 0;

		private const byte FIRST_FRAME = 16;

		private const byte CONSECUTIVE_FRAME = 32;

		private const byte FLOW_CONTROL_FRAME = 48;

		private const byte MAX_FF_DL = 226;

		private CANMessage KWP2000_Send;

		private CANMessage KWP2000_Receive;

		private byte BlockSize = 16;

		private byte SeperationTimeMin = 1;

		private uint ff_dl;

		private int sn;

		private int sleep = 1;

		private uint packetcount;

		private byte bs;

		private byte fs;

		public List<byte> al_receive = new List<byte>();

		public uint datacount;

		public bool Response;

		public bool FlowControl;

		public AutoResetEvent ev_Response;

		public List<byte> AL_receive
		{
			get
			{
				return al_receive;
			}
		}

		public KWP2000(CANMessage sndMsg, CANMessage rcvMsg)
		{
			ev_Response = new AutoResetEvent(false);
			KWP2000_Send = sndMsg;
			KWP2000_Receive = rcvMsg;
			KWP2000_Receive.MessageReceive += OnMessageReceive;
		}

		private ConfigBase.EOk SendSingleFrame(int singleframedatal, ref List<byte> data)
		{
			KWP2000_Send.Data[0] = (byte)singleframedatal;
			int i;
			for (i = 0; i < singleframedatal; i++)
			{
				KWP2000_Send.Data[i + 1] = data[i];
			}
			for (; i < 7; i++)
			{
				KWP2000_Send.Data[i + 1] = byte.MaxValue;
			}
			KWP2000_Send.FireMessageSend();
			return ConfigBase.EOk.eSendOk;
		}

		private ConfigBase.EOk SendFirstFrame(int firstframedatal_receivelength, ref List<byte> data)
		{
			KWP2000_Send.Data[0] = (byte)((firstframedatal_receivelength >> 8) | 0x10);
			KWP2000_Send.Data[1] = (byte)(firstframedatal_receivelength & 0xFF);
			KWP2000_Send.Data[2] = data[0];
			KWP2000_Send.Data[3] = data[1];
			KWP2000_Send.Data[4] = data[2];
			KWP2000_Send.Data[5] = data[3];
			KWP2000_Send.Data[6] = data[4];
			KWP2000_Send.Data[7] = data[5];
			KWP2000_Send.FireMessageSend();
			return ConfigBase.EOk.eSendOk;
		}

		private ConfigBase.EOk SendConsecutiveFrame(byte sequencenumber, ref List<byte> data, uint startbyte, uint count)
		{
			KWP2000_Send.Data[0] = (byte)((sequencenumber & 0xF) | 0x20);
			uint num;
			for (num = 0u; num < count; num++)
			{
				KWP2000_Send.Data[num + 1] = data[(int)(num + startbyte)];
			}
			for (; num < 7; num++)
			{
				KWP2000_Send.Data[num + 1] = byte.MaxValue;
			}
			KWP2000_Send.FireMessageSend();
			return ConfigBase.EOk.eSendOk;
		}

		private ConfigBase.EOk SendFlowControlFrame(uint flowstatus)
		{
			KWP2000_Send.Data[0] = (byte)(flowstatus | 0x30);
			KWP2000_Send.Data[1] = BlockSize;
			KWP2000_Send.Data[2] = SeperationTimeMin;
			KWP2000_Send.Data[3] = byte.MaxValue;
			KWP2000_Send.Data[4] = byte.MaxValue;
			KWP2000_Send.Data[5] = byte.MaxValue;
			KWP2000_Send.Data[6] = byte.MaxValue;
			KWP2000_Send.Data[7] = byte.MaxValue;
			KWP2000_Send.FireMessageSend();
			return ConfigBase.EOk.eSendOk;
		}

		public ConfigBase.EOk SendMessage(ref List<byte> data)
		{
			uint num = 1u;
			uint num2 = 0u;
			if (KWP2000_Send == null || KWP2000_Receive == null)
			{
				throw new Exception("KWP send/receive messages not initialized.");
			}
			if (data == null)
			{
				throw new Exception("KWP send messages not defined.");
			}
			if (data.Count < 1)
			{
				return ConfigBase.EOk.eSendNOk;
			}
			byte b = (byte)data.Count;
			Response = false;
			ev_Response.Reset();
			if (b < 8)
			{
				return SendSingleFrame(b, ref data);
			}
			FlowControl = false;
			if (SendFirstFrame(b, ref data) == ConfigBase.EOk.eSendNOk)
			{
				return ConfigBase.EOk.eSendNOk;
			}
			num2 += 6;
			int num3 = 0;
			while (!FlowControl && num3 < 3000)
			{
				Thread.Sleep(sleep);
				num3 += sleep;
			}
			if (!FlowControl)
			{
				return ConfigBase.EOk.eSendNOk;
			}
			int num4 = 0;
			while (true)
			{
				if (num > 15)
				{
					num = 0u;
				}
				if (num4 == bs)
				{
					num3 = 0;
					while (!FlowControl && num3 < 300)
					{
						Thread.Sleep(sleep);
						num3 += sleep;
					}
					if (!FlowControl)
					{
						return ConfigBase.EOk.eSendNOk;
					}
					FlowControl = false;
					num4 = 0;
				}
				if (SeperationTimeMin > 0)
				{
					Thread.Sleep(SeperationTimeMin);
				}
				if (b - num2 <= 7)
				{
					break;
				}
				if (SendConsecutiveFrame((byte)num, ref data, num2, 7u) == ConfigBase.EOk.eSendNOk)
				{
					return ConfigBase.EOk.eSendNOk;
				}
				num2 += 7;
				num++;
				num4++;
			}
			if (SendConsecutiveFrame((byte)num, ref data, num2, b - num2) == ConfigBase.EOk.eSendNOk)
			{
				return ConfigBase.EOk.eSendNOk;
			}
			return ConfigBase.EOk.eSendOk;
		}

		private void MessageHandler(uint datalength, ref List<byte> data)
		{
			if (datacount == 3 && data[2] == 120 && data[0] == 127)
			{
				al_receive.Clear();
				return;
			}
			Response = true;
			ev_Response.Set();
		}

		public void OnMessageReceive(object o)
		{
			if (!(o is CANMessage))
			{
				return;
			}
			CANMessage cANMessage = (CANMessage)o;
			if (cANMessage.ID != KWP2000_Receive.ID)
			{
				return;
			}
			switch (cANMessage.Data[0] & 0xF0)
			{
			case 0:
			{
				datacount = (uint)(cANMessage.Data[0] & 0xF);
				if (datacount > 7)
				{
					datacount = 7u;
				}
				al_receive.Clear();
				for (int k = 0; k < datacount; k++)
				{
					al_receive.Add(cANMessage.Data[k + 1]);
				}
				MessageHandler(datacount, ref al_receive);
				ff_dl = 0u;
				break;
			}
			case 16:
				if (ff_dl != 226)
				{
					al_receive.Clear();
					ff_dl = cANMessage.Data[1];
					for (int l = 2; l < 8; l++)
					{
						al_receive.Add(cANMessage.Data[l]);
					}
					datacount = 6u;
					sn = -1;
					packetcount = 0u;
					SendFlowControlFrame(0u);
				}
				else
				{
					ff_dl = cANMessage.Data[1];
					for (int m = 4; m < 8; m++)
					{
						al_receive.Add(cANMessage.Data[m]);
					}
					datacount = 6u;
					sn = -1;
					packetcount = 0u;
					SendFlowControlFrame(0u);
				}
				break;
			case 32:
				sn = cANMessage.Data[0] & 0xF;
				packetcount++;
				if (ff_dl - datacount > 7)
				{
					for (int i = 1; i < 8; i++)
					{
						al_receive.Add(cANMessage.Data[i]);
					}
					datacount += 7u;
					if (packetcount == BlockSize)
					{
						SendFlowControlFrame(0u);
						packetcount = 0u;
					}
				}
				else
				{
					for (int j = 1; j < ff_dl - datacount + 1; j++)
					{
						al_receive.Add(cANMessage.Data[j]);
					}
					datacount += ff_dl - datacount;
					if (ff_dl != 226)
					{
						MessageHandler(datacount, ref al_receive);
					}
				}
				break;
			case 48:
				fs = (byte)(cANMessage.Data[0] & 0xF);
				bs = cANMessage.Data[1];
				SeperationTimeMin = cANMessage.Data[2];
				FlowControl = true;
				break;
			}
		}
	}
}
